package org.jmc.refmanager.domain.model;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.Size;

@Entity
@Table(name="users",
		uniqueConstraints = { @UniqueConstraint(columnNames={"USERNAME"})
		})
@NamedQueries({
	@NamedQuery(name = User.COUNT_BY_OWNER, 
			query = "SELECT count(*) FROM User u1, User u2 WHERE (u1.validationScope=u2.validationScope AND u2.matricule=?1) AND u1.matricule <> ?1"),
	@NamedQuery(name = User.COUNT_BY_OWNER_AND_MATRICULE, 
			query = "SELECT count(*) FROM User u1, User u2 WHERE (u1.validationScope=u2.validationScope AND u2.matricule=?1) AND u1.matricule <> ?1 AND UPPER(u1.matricule) like UPPER(?2)"),
	@NamedQuery(name = User.GET_BY_MATRICULE,
			query = "SELECT u FROM User u WHERE UPPER(u.matricule)=UPPER(:matricule)"),
	@NamedQuery(name = User.FIND_BY_MATRICULE,
			query = "SELECT u FROM User u WHERE UPPER(u.matricule) like UPPER(?1)"),
	@NamedQuery(name = User.COUNT_BY_MATRICULE,
			query = "SELECT count(*) FROM User u WHERE UPPER(u.matricule) like UPPER(?1)"),
	@NamedQuery(name = User.FIND_BY_OWNER,
			query = "SELECT u1 FROM User u1, User u2 WHERE (u1.validationScope=u2.validationScope AND u2.matricule=?1 AND u1.matricule <> ?1)"),
	@NamedQuery(name = User.FIND_BY_OWNER_AND_MATRICULE,
			query = "SELECT u1 FROM User u1, User u2 WHERE (u1.validationScope=u2.validationScope AND u2.matricule=?1) AND u1.matricule <> ?1 AND UPPER(u1.matricule) like UPPER(?2)")
})
public class User implements Serializable {
	private static final long serialVersionUID = 1L;
	public final static String GET_BY_MATRICULE = "User.getByMatricule";
	public final static String FIND_BY_MATRICULE = "User.findByMatricule";
	public final static String FIND_BY_OWNER = "User.findByOwner";
	public final static String FIND_BY_OWNER_AND_MATRICULE = "User.findByOwnerAndMatricule";
	public final static String COUNT_BY_OWNER = "User.countByOwner";
	public final static String COUNT_BY_OWNER_AND_MATRICULE = "User.countByOwnerAndMatricule";
	public final static String COUNT_BY_MATRICULE = "User.countByMatricule";
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="USER_ID")
	private Integer id;
	
	@Column(name="USERNAME", unique=true, nullable=false, length=50)
	private String matricule;
	
	@Column(name="PASSWORD", nullable=false)
	@Size(min=6, message="La longueur minimale du mot de passe est de {min} caractères")
	private String password;

	@Column(name="ENABLED", nullable=false)
	private boolean enabled;

	@Column(name="INIT", nullable=true)
	private boolean initialized;

	@ManyToOne
    @JoinColumn(name="ROLE_ID", nullable=false)
	private Role role;

	@ManyToMany(cascade = CascadeType.ALL)
	@JoinTable(name = "tasks",
			joinColumns = { @JoinColumn(name="USER_ID") },
			inverseJoinColumns = { @JoinColumn(name="CHANGE_ID") } )
	private Set<Change> myTasks = new HashSet<Change>(0);

	// Ne pas supprimer le service lorsque l'on supprime l'utilisateur
	@ManyToOne(fetch=FetchType.EAGER, optional=true)
	@JoinColumns( { @JoinColumn(name = "scopeId") })
	private OrgUnit validationScope;
	

	public void addTask(Change change) {
		myTasks.add(change);
	}

	public void removeTask(Change change) {
		myTasks.remove(change);
	}

	/**
	 * @return the id
	 */
	public Integer getId() {
		return id;
	}

	/**
	 * @param id the id to set
	 */
	public void setId(final Integer id) {
		this.id = id;
	}

	/**
	 * @return the matricule
	 */
	public String getMatricule() {
		return matricule;
	}

	/**
	 * @param matricule the matricule to set
	 */
	public void setMatricule(final String matricule) {
		this.matricule = matricule;
	}

	/**
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * @param password the password to set
	 */
	public void setPassword(final String password) {
		this.password = password;
	}

	/**
	 * @return the enabled
	 */
	public boolean isEnabled() {
		return enabled;
	}

	/**
	 * @param enabled the enabled to set
	 */
	public void setEnabled(final boolean enabled) {
		this.enabled = enabled;
	}

	/**
	 * @return the initialized
	 */
	public boolean isInitialized() {
		return initialized;
	}

	/**
	 * @param initialized the initialized to set
	 */
	public void setInitialized(final boolean initialized) {
		this.initialized = initialized;
	}

	public Role getRole() {
		return role;
	}

	public void setRole(final Role role) {
		this.role = role;
	}

	public Set<Change> getMyTasks() {
		return this.myTasks;
	}

	public void setMyTasks(Set<Change> myTasks) {
		this.myTasks = myTasks;
	}

	/**
	 * @param validationScope the validationScope to set
	 */
	public void setValidationScope(OrgUnit validationScope) {
		this.validationScope = validationScope;
	}

	/**
	 * @return the validationScope
	 */
	public OrgUnit getValidationScope() {
		return validationScope;
	}
}
